/**
 * 
 */
package org.statewalker.parser.turtle.tokenizer;

import org.statewalker.parser.turtle.TurtleDict1;
import org.statewalker.parser.turtle.tokenizer.CharacterTokenizer.CharacterReader;
import org.statewalker.parser.turtle.tokenizer.CharacterTokenizer.CharacterToken;
import org.statewalker.tokenizer.CharStream;
import org.statewalker.tokenizer.ITokenizer;
import org.statewalker.tokenizer.StreamToken;
import org.statewalker.tokenizer.CharStream.Marker;

/**
 * <pre>
 * http://www.w3.org/TeamSubmission/turtle/#uriref
 * [28] uriref  ::= '<' relativeURI '>'
 * [34] relativeURI ::= ucharacter*
 * [41] ucharacter  ::=  ( character - #x3E ) | '\\>'
 * [38] character   ::=  '\\u' hex hex hex hex | '\\U' hex hex hex hex hex hex hex hex | '\\' | [#x20-#x5B] | [#x5D-#x10FFFF]
 * </pre>
 * @author kotelnikov
 */
public class UriRefTokenizer implements ITokenizer {

    public static class UriRefToken extends StreamToken {

        private String fRelativeUri;

        public UriRefToken(String key, CharStream stream, Marker marker) {
            super(key, stream, marker);
        }

        public String getRelativeUri() {
            return fRelativeUri;
        }

        public void setRelativeUri(String relativeUri) {
            fRelativeUri = relativeUri;
        }

    }

    public final static UriRefTokenizer INSTANCE = new UriRefTokenizer();

    private String fKey;

    private CharacterTokenizer fUCharTokenizer;

    public UriRefTokenizer() {
        this(TurtleDict1._URI_REF);
    }

    /**
     * 
     */
    public UriRefTokenizer(String key) {
        fKey = key;
        fUCharTokenizer = new CharacterTokenizer(key, new CharacterReader() {
            @Override
            public int readNextChar(CharStream stream) {
                char ch = stream.getChar();
                if (ch == 0x3E)
                    return -1;
                return super.readNextChar(stream);
            }
        });
    }

    public StreamToken read(CharStream stream) {
        if (stream.getChar() != '<')
            return null;
        StringBuilder buf = new StringBuilder();
        UriRefToken result = null;
        Marker marker = stream.markPosition();
        try {
            stream.incPos();
            while (true) {
                char ch = stream.getChar();
                if (ch == '>') {
                    stream.incPos();
                    break;
                } else if (ch == '\\') {
                    stream.incPos();
                    ch = stream.getChar();
                    if (ch != '>') {
                        buf.append('\\');
                        buf.append(ch);
                    } else {
                        buf.append(ch);
                    }
                    stream.incPos();
                    continue;
                }
                CharacterToken token = (CharacterToken) fUCharTokenizer
                    .read(stream);
                if (token != null) {
                    String text = token.getValue();
                    buf.append(text);
                } else {
                    break;
                }
            }
            result = new UriRefToken(fKey, stream, marker);
            result.setRelativeUri(buf.toString());
            return result;
        } finally {
            marker.close(result == null);
        }
    }

}
